#include "taskqueue.h"
#include <func.h>

void queue_init(taskqueue_t* q)
{
    pthread_cond_init(&q->notfull,NULL);
    pthread_cond_init(&q->notempty,NULL);
    q->front=NULL;
    q->rear=NULL;
    q->size=0;
    q->maxsize=TASK_MAXNUM;
    q->exitflag=PTHREAD_NOTEXIT;
    pthread_mutex_init(&q->mutex,NULL);
}

void queue_destroy(taskqueue_t * q)
{
    pthread_cond_destroy(&q->notfull);
    pthread_mutex_destroy(&q->mutex);
    pthread_cond_destroy(&q->notempty);
    task_t* behind;
    while(!isempty(q)){
        behind=q->front->next;
        free(q->front);
        q->front=behind;
        --q->size;
        if(q->size==0){
            q->rear=NULL;
        }
    }
}

void enqueue(taskqueue_t* q,int fd)
{
    int ret=pthread_mutex_lock(&q->mutex);
    PTHREAD_ERROR_CHECK(ret,0);
    while(!q->exitflag && q->size==q->maxsize){
        pthread_cond_wait(&q->notfull,&q->mutex);
    }
    if(!q->exitflag){
        task_t* newnode=(task_t*)calloc(1,sizeof(task_t));
        newnode->peerfd=fd;
        newnode->next=NULL;
        if(isempty(q)){
            q->front=q->rear=newnode;
        }else{
            q->rear->next=newnode;
            q->rear=newnode;
        }
        ++q->size;
    }
    ret=pthread_mutex_unlock(&q->mutex);
    PTHREAD_ERROR_CHECK(ret,0);
    ret=pthread_cond_signal(&q->notempty);
    PTHREAD_ERROR_CHECK(ret,0);
}

int dequeue(taskqueue_t* q)
{
    int ret=pthread_mutex_lock(&q->mutex);
    PTHREAD_ERROR_CHECK(ret,0);
    while(!q->exitflag&& isempty(q)){
        pthread_cond_wait(&q->notempty,&q->mutex);
    }
    int fd=-1;
    if(!q->exitflag){
        task_t* cur=q->front;
        fd=q->front->peerfd;
        if(q->size==1){
            q->front=q->rear=NULL;
        }else{
            q->front=q->front->next;
        }
        free(cur);
        --q->size;
    }
    ret=pthread_mutex_unlock(&q->mutex);
    PTHREAD_ERROR_CHECK(ret,0);
    ret=pthread_cond_signal(&q->notfull);
    PTHREAD_ERROR_CHECK(ret,0);
    return fd;
}

int isempty(taskqueue_t* q)
{
    return q->size == 0;
}

int queuesize(taskqueue_t* q)
{
    return q->size;
}

void wakeupqueue(taskqueue_t* q)
{
    q->exitflag=PTHREAD_EXIT;
    int ret=pthread_cond_broadcast(&q->notfull);
    PTHREAD_ERROR_CHECK(ret,0);
    ret=pthread_cond_broadcast(&q->notempty);
    PTHREAD_ERROR_CHECK(ret,0);
}
